package com.danicsoft.daide.command;

import com.danicsoft.daide.token.TokenGroup;

/**
 * Implements a command as recieved or sent from a client or server. This class
 * correctly integrates with TokenIO to create proper input and output. A new
 * command is very easy to create. Simply override the three abtract methods (<code>getType()</code>,
 * <code>toString()</code> and <code>doIO()</code>). See their method
 * descriptions for more details. Note that a subclass of command cannot, in
 * general, initialize variables before doIO is called. This is because doIO is
 * called from the constructor, which is called before any initialization in the
 * subclass. For this purpose, a method <code>initialize</code> has been
 * created that subclasses can override and do any initialization in. It is
 * basically a constructor.
 * 
 * @author Daniel Yule (daniel.yule@gmail.com)
 * @version 1.0
 */
public abstract class Command implements IOTarget {

	/**
	 * Provide a nicely formatted string describing the contents of this
	 * message.
	 * 
	 * @return A String describing the contents of this message.
	 * @see java.lang.Object#toString()
	 */
	@Override
	public abstract String toString();

	/**
	 * The status of this message (accpted, rejected, transmitting)
	 */
	private COMMAND_STATUS status = COMMAND_STATUS.TRANSMITTING;

	/**
	 * Create a new Command, loading from the tokens specified. This constructor
	 * should be called by all subclasses wishing to load themselves from a
	 * recieved command (And I can't think of a subclass that wouldn't).
	 * 
	 * @param tokens
	 *        The <code>TokenGroup</code> that describes this command. The
	 *        command token corresponding to this <code>Command</code>'s code
	 *        has already been removed.
	 * @throws ParseException
	 *         If there was an error parsing this command.
	 */
	public Command(TokenGroup tokens) throws ParseException {
		initialize();
		TokenIO.doInput(tokens, this);
	}

	/**
	 * Construct a command. Call this constructor if you are going to initialize
	 * the values of this command and then send it.
	 */
	public Command() {

	}

	/**
	 * Return a new instance of this command. This default implementation tries
	 * to use reflection to create a new instance. This will work if the
	 * subclass is a) not a non-static inner class and b) has a default
	 * constructor. If either of these two things are untrue, this method will
	 * return null, and should be overridden by the offending subclass.
	 * 
	 * @return A new instance of this object.
	 * @see com.danicsoft.daide.command.IOTarget#newInstance()
	 */
	public IOTarget newInstance() {
		try {
			return getClass().newInstance();
		}
		catch (InstantiationException e) {

		}
		catch (IllegalAccessException e) {

		}
		return null;
	}

	/**
	 * This method is called prior to <code>doIO()</code> when doing input to
	 * allow classes to initialize themselves, as they are required to do input
	 * before their constructor is completed. If a command has list members, for
	 * example, they should be initialized here, beause otherwise they won't be
	 * before they're needed.
	 */
	public void initialize() {

	}

	/**
	 * Get the status of this command.
	 * 
	 * @return This command's status.
	 */
	public COMMAND_STATUS getStatus() {
		return status;
	}

	/**
	 * Returns true if this command can be reduced (ie is wrapping another
	 * command). This is for commands such as YES, REJ or NOT.
	 * 
	 * @return True of this command is Reducible, false otherwise.
	 */
	public boolean isReducible() {
		return false;
	}

	/**
	 * Output this command to the token group specified. This method wraps the
	 * <code>TokenIO</code> output method, so that outside classes really need
	 * not know anything about its workings it all.
	 * 
	 * @return A <code>TokenGroup</code> containing the information for this
	 *         command. This <code>TokenGroup</code> can then be sent to a
	 *         client or server.
	 */
	public TokenGroup output() {
		try {
			return TokenIO.doOutput(this);
		}
		catch (ParseException e) {
			//TODO log this as a serious problem
		}
		return new TokenGroup();
	}

	/**
	 * Gets the type of this command.
	 * 
	 * @return A byte that represents the type of this command.
	 */
	public abstract byte getType();

	/**
	 * Sets the status of this command. Should only be used by Reducible
	 * commands to set the status of the command they wrap as they are being
	 * reduced.
	 * 
	 * @param status
	 *        The new status of this command.
	 */
	protected void setStatus(COMMAND_STATUS status) {
		this.status = status;
	}

}
